package com.punai.Incomedata.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeNodeConfig;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.punai.Incomedata.service.IProLibIncomeBaseService;
import com.punai.Incomedata.vo.EndSettlementVo;
import com.punai.Incomedata.vo.IProLibIncomeBaseVo;
import com.punai.Incomedata.vo.StartBudgetVo;
import com.punai.common.constant.HttpStatus;
import com.punai.common.core.page.TableDataInfo;
import com.punai.common.utils.NumberUtil;
import com.punai.externalccb.constants.CCBConstants;
import com.punai.externalccb.domain.*;
import com.punai.externalccb.mapper.*;
import com.punai.prodatalibrary.domain.bo.GlobalProInfoBo;
import com.punai.prodatalibrary.service.ILibProjectInfoService;
import org.apache.commons.collections4.ListValuedMap;
import org.apache.commons.collections4.multimap.ArrayListValuedHashMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;

@Service
@Transactional
public class IroLibIncomeBaseServiceImpl<T extends IProLibIncomeBaseVo> implements IProLibIncomeBaseService<T> {

    @Autowired
    private ILibProjectInfoService libProjectInfoService;
    @Autowired
    private EcoBidnodeMapper bidnodeMapper;
    @Autowired
    private EcoSummaryMapper summaryMapper;
    @Autowired
    private EcoBqitemMapper bqitemMapper;
    @Autowired
    private EcoMeasureitemMapper measureitemMapper;
    @Autowired
    private EcoOtheritemMapper otheritemMapper;
    @Autowired
    private EcoResourceMapper resourceMapper;
    @Override
    public List<? extends IProLibIncomeBaseVo> selectMainTableData(T vo) {
        List<GlobalProInfoBo> infoList = libProjectInfoService.selectInfoList(new GlobalProInfoBo(){{
            setType(vo.getType());
            setProId(vo.getProId());
            setProjectCode(vo.getProCode());
            setProjectName(vo.getProName());
            setProjectState(vo.getProjectState());
            setProjectDept(vo.getProjectDept());
        }});
        List<IProLibIncomeBaseVo> res = new ArrayList<>();
        for (GlobalProInfoBo globalProInfoBo : infoList) {
            String ccbType = vo.getCcbType();
            IProLibIncomeBaseVo convert = IProLibIncomeBaseVo.convert(globalProInfoBo);
            if(CCBConstants.CCB_TYPE.KGYSSJ.getCode().equals(ccbType)){
                StartBudgetVo startBudgetVo = new StartBudgetVo();
                BeanUtil.copyProperties(convert,startBudgetVo);
                res.add(startBudgetVo);
            }
            if (CCBConstants.CCB_TYPE.JGJSSJ.getCode().equals(ccbType)) {
                EndSettlementVo endSettlementVo = new EndSettlementVo();
                BeanUtil.copyProperties(convert, endSettlementVo);
                res.add(endSettlementVo);
            }
        }
        return res;
    }



    @Override
    public TableDataInfo selectMainTableDataSize(T vo) {
        List<GlobalProInfoBo> infoList = libProjectInfoService.selectInfoList(new GlobalProInfoBo(){{
            setType(vo.getType());
            setProId(vo.getProId());
            setProjectCode(vo.getProCode());
            setProjectName(vo.getProName());
            setProjectState(vo.getProjectState());
            setProjectDept(vo.getProjectDept());
        }});
        List<IProLibIncomeBaseVo> res = new ArrayList<>();
        for (GlobalProInfoBo globalProInfoBo : infoList) {
            String ccbType = vo.getCcbType();
            IProLibIncomeBaseVo convert = IProLibIncomeBaseVo.convert(globalProInfoBo);
            if(CCBConstants.CCB_TYPE.KGYSSJ.getCode().equals(ccbType)){
                StartBudgetVo startBudgetVo = new StartBudgetVo();
                BeanUtil.copyProperties(convert,startBudgetVo);
                res.add(startBudgetVo);
            }
            if (CCBConstants.CCB_TYPE.JGJSSJ.getCode().equals(ccbType)) {
                EndSettlementVo endSettlementVo = new EndSettlementVo();
                BeanUtil.copyProperties(convert, endSettlementVo);
                res.add(endSettlementVo);
            }
        }
        GlobalProInfoBo bo = new GlobalProInfoBo();
        bo.setType(vo.getType());
        bo.setProId(vo.getProId());
        bo.setProjectCode(vo.getProCode());
        bo.setProjectName(vo.getProName());
        bo.setProjectState(vo.getProjectState());
        bo.setProjectDept(vo.getProjectDept());
        Integer total = libProjectInfoService.selectInfoListTotal(bo);
        TableDataInfo rspData = new TableDataInfo();
        rspData.setCode(HttpStatus.SUCCESS);
        rspData.setMsg("查询成功");
        rspData.setRows(res);
        rspData.setTotal(total);
        return rspData;
    }

    @Override
    public List<Tree<Integer>> selectCbBidNodeList(T vo) {
        String ccbType = vo.getCcbType();
        String proId = vo.getProId();
        List<EcoBidnode> ecoBidnodes = bidnodeMapper.selectList(Wrappers.<EcoBidnode>lambdaQuery()
                .eq(EcoBidnode::getStagetype, ccbType)
                .eq(EcoBidnode::getProId, proId)
                .orderByAsc(EcoBidnode::getOid)
        );
        List<TreeNode<Integer>> nodeList = CollUtil.newArrayList();
        for (EcoBidnode root : ecoBidnodes) {
            TreeNode<Integer> treeNode = new TreeNode<>();
            treeNode.setId(root.getOid());
            treeNode.setName(root.getNodename());
            treeNode.setParentId(root.getPid());
            treeNode.setWeight(root.getOid());
            treeNode.setExtra(new HashMap<String, Object>(){{
                put("nodetype",root.getNodetype());
                put("oid",root.getId());
            }});
            nodeList.add(treeNode);
        }
        TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
        return TreeUtil.build(nodeList, 0, treeNodeConfig,
                (treeNode, tree) -> {
                    tree.setId(treeNode.getId());
                    tree.setParentId(treeNode.getParentId());
                    tree.setWeight(treeNode.getWeight());
                    tree.setName(treeNode.getName());
                    tree.putExtra("extra", treeNode.getExtra());
                });
    }

    @Override
    public List<Object> selectDetailTableDataList(T vo) {
        List<Object> list = new ArrayList<>();
        String tabType = vo.getTabType();
        String bidnodeOid = vo.getBidnodeOid();
        EcoBidnode ecoBidnode = bidnodeMapper.selectById(bidnodeOid);
        if(Tab_Type.zjhz.getCode().equals(tabType) && (ecoBidnode.getNodetype() == 0 || ecoBidnode.getNodetype() == 1)){
            List<EcoBidnode> ecoBidnodes = bidnodeMapper.selectList(Wrappers.<EcoBidnode>lambdaQuery()
                    .eq(EcoBidnode::getStagetype, ecoBidnode.getStagetype())
                    .eq(EcoBidnode::getProId, ecoBidnode.getProId())
                    .orderByAsc(EcoBidnode::getOid)
            );
            ListValuedMap<Integer, EcoBidnode> valuedHashMap = new ArrayListValuedHashMap<>();
            ecoBidnodes.forEach(v-> valuedHashMap.put(v.getPid(), v));
            List<EcoBidnode> nodes = Collections.singletonList(ecoBidnode);
            Map<String, Object> root = this.convert(ecoBidnode, null);
            for (EcoBidnode node : nodes) {
                Map<String, Object> convert = this.convert(node, root);
                getBidNodeChildren(convert, valuedHashMap, root);
                list.add(convert);
            }
        }
        if (Tab_Type.zjhz.getCode().equals(tabType) && ecoBidnode.getNodetype() == 2) {
            List<EcoSummary> all = summaryMapper.selectList(Wrappers.<EcoSummary>lambdaQuery()
                    .eq(EcoSummary::getBidnodeid, ecoBidnode.getOid())
                    .eq(EcoSummary::getProId, ecoBidnode.getProId())
                    .eq(EcoSummary::getStagetype, ecoBidnode.getStagetype())
                    .orderByAsc(EcoSummary::getOid)
            );
            all.forEach(v-> list.add(BeanUtil.beanToMap(v)));
        }
        if (Tab_Type.fbfx.getCode().equals(tabType)) {
            List<EcoBqitem> all = bqitemMapper.selectList(Wrappers.<EcoBqitem>lambdaQuery()
                    .eq(EcoBqitem::getBidnodeid, ecoBidnode.getOid())
                    .eq(EcoBqitem::getProId, ecoBidnode.getProId())
                    .eq(EcoBqitem::getStagetype, ecoBidnode.getStagetype())
                    .orderByAsc(EcoBqitem::getBqitemid)
            );
            ListValuedMap<Integer, EcoBqitem> valuedHashMap = new ArrayListValuedHashMap<>();
            all.forEach(v -> valuedHashMap.put(v.getBqitempid(), v));
            List<EcoBqitem> nodes = valuedHashMap.get(0);
            for (EcoBqitem node : nodes) {
                Map<String, Object> convert = this.convert(node);
                BigDecimal zhsrhjOfRe = getBqitemChildren(convert, valuedHashMap);
                if(zhsrhjOfRe != null) convert.put("zhsrhj", zhsrhjOfRe);
                list.add(convert);
            }
        }
        if (Tab_Type.csxm.getCode().equals(tabType)) {
            List<EcoMeasureitem> all = measureitemMapper.selectList(Wrappers.<EcoMeasureitem>lambdaQuery()
                    .eq(EcoMeasureitem::getBidnodeid, ecoBidnode.getOid())
                    .eq(EcoMeasureitem::getProId, ecoBidnode.getProId())
                    .eq(EcoMeasureitem::getStagetype, ecoBidnode.getStagetype())
                    .orderByAsc(EcoMeasureitem::getMeasureitemid)
            );
            ListValuedMap<Integer, EcoMeasureitem> valuedHashMap = new ArrayListValuedHashMap<>();
            all.forEach(v -> valuedHashMap.put(v.getMeasureitempid(), v));
            List<EcoMeasureitem> nodes = valuedHashMap.get(0);
            for (EcoMeasureitem node : nodes) {
                Map<String, Object> convert = this.convert(node);
                getMeasureitemChildren(convert, valuedHashMap);
                list.add(convert);
            }
        }
        if (Tab_Type.qtxm.getCode().equals(tabType)) {
            List<EcoOtheritem> all = otheritemMapper.selectList(Wrappers.<EcoOtheritem>lambdaQuery()
                    .eq(EcoOtheritem::getBidnodeid, ecoBidnode.getOid())
                    .eq(EcoOtheritem::getProId, ecoBidnode.getProId())
                    .eq(EcoOtheritem::getStagetype, ecoBidnode.getStagetype())
                    .orderByAsc(EcoOtheritem::getOid)
            );
            ListValuedMap<Integer, EcoOtheritem> valuedHashMap = new ArrayListValuedHashMap<>();
            all.forEach(v -> valuedHashMap.put(v.getOpid(), v));
            List<EcoOtheritem> nodes = valuedHashMap.get(0);
            for (EcoOtheritem node : nodes) {
                Map<String, Object> convert = this.convert(node);
                getOtheritemChildren(convert, valuedHashMap);
                list.add(convert);
            }
        }
        if (Tab_Type.rcjhz.getCode().equals(tabType)) {
            List<EcoResource> all = resourceMapper.selectList(Wrappers.<EcoResource>lambdaQuery()
                    .eq(EcoResource::getBidnodeid, ecoBidnode.getOid())
                    .eq(EcoResource::getProId, ecoBidnode.getProId())
                    .eq(EcoResource::getStagetype, ecoBidnode.getStagetype())
                    .orderByAsc(EcoResource::getResourceid)
            );
            for (EcoResource node : all) {
                Map<String, Object> convert = this.convert(node);
                list.add(convert);
            }
        }
        return list;
    }


    public Map<String, Object> convert(EcoBidnode bidNode, Map<String, Object> root) {
        Map<String, Object> re = BeanUtil.beanToMap(bidNode);
        re.put("zjje", bidNode.getAmount());
        re.put("zjzb", BigDecimal.valueOf(100));
        if (root != null) {
            re.put("zjzb", NumberUtil.divide(NumberUtil.getValue(re.get("zjje")),
                            4,
                            NumberUtil.getValue(root.get("zjje")))
                    .multiply(BigDecimal.valueOf(100)));
        }
        return re;
    }

    private void getBidNodeChildren(Map<String, Object> p, ListValuedMap<Integer, EcoBidnode> valuedHashMap, Map<String, Object> root) {
        List<EcoBidnode> nodes = valuedHashMap.get(Integer.valueOf(StrUtil.toString(p.get("oid"))));
        if (nodes != null) {
            List<Object> child = new ArrayList<>();
            for (EcoBidnode node : nodes) {
                Map<String, Object> convert = this.convert(node, root);
                getBidNodeChildren(convert, valuedHashMap, root);
                child.add(convert);
            }
            p.put("children", child);
        }
    }

    public Map<String, Object> convert(EcoBqitem bqitem) {
        Map<String, Object> beanToMap = BeanUtil.beanToMap(bqitem);
        beanToMap.put("zhsrhj",NumberUtil.multiply(bqitem.getQuantity(), bqitem.getRate(), 4));
        return beanToMap;
    }

    private BigDecimal getBqitemChildren(Map<String,Object> p, ListValuedMap<Integer, EcoBqitem> pMap) {
        List<EcoBqitem> roots = pMap.get(Integer.valueOf(StrUtil.toString(p.get("bqitemid"))));
        BigDecimal zhsrhj = null;
        if (roots != null) {
            if(roots.size()>0) zhsrhj = BigDecimal.ZERO;
            List<Object> child = new ArrayList<>();
            for (EcoBqitem root : roots) {
                Map<String, Object> convert = this.convert(root);
                List<EcoBqitem> bqitems = pMap.get(root.getBqitemid());
                BigDecimal zhsrhjOfRe = getBqitemChildren(convert, pMap);
                if(bqitems.size()>0){
                    convert.put("zhsrhj", zhsrhjOfRe);
                }
                zhsrhj = NumberUtil.add(zhsrhj, NumberUtil.getValue(convert.get("zhsrhj")),4);
                child.add(convert);
            }
            p.put("children", child);
        }
        return zhsrhj;
    }

    public Map<String, Object> convert(EcoMeasureitem measureitem) {
        Map<String, Object> beanToMap = BeanUtil.beanToMap(measureitem);
        beanToMap.put("rgfhj",NumberUtil.multiply(measureitem.getQuantity(), measureitem.getLaborrate()));
        beanToMap.put("clfhj",NumberUtil.multiply(measureitem.getQuantity(), measureitem.getMaterialrate()));
        beanToMap.put("jxfhj",NumberUtil.multiply(measureitem.getQuantity(), measureitem.getMachinerate()));
        return beanToMap;
    }

    private void getMeasureitemChildren(Map<String, Object> p, ListValuedMap<Integer, EcoMeasureitem> valuedHashMap) {
        List<EcoMeasureitem> roots = valuedHashMap.get(Integer.valueOf(StrUtil.toString(p.get("measureitemid"))));
        if (roots != null) {
            List<Object> child = new ArrayList<>();
            for (EcoMeasureitem root : roots) {
                Map<String, Object> convert = this.convert(root);
                getMeasureitemChildren(convert, valuedHashMap);
                child.add(convert);
            }
            p.put("children", child);
        }
    }

    private Map<String, Object> convert(EcoOtheritem otheritem) {
        return BeanUtil.beanToMap(otheritem);
    }

    private void getOtheritemChildren(Map<String, Object> p, ListValuedMap<Integer, EcoOtheritem> valuedHashMap) {
        List<EcoOtheritem> roots = valuedHashMap.get(Integer.valueOf(StrUtil.toString(p.get("oid"))));
        if (roots != null) {
            List<Object> child = new ArrayList<>();
            for (EcoOtheritem root : roots) {
                Map<String, Object> convert = this.convert(root);
                getOtheritemChildren(convert, valuedHashMap);
                child.add(convert);
            }
            p.put("children", child);
        }
    }

    private Map<String, Object> convert(EcoResource resource) {
        Map<String, Object> beanToMap = BeanUtil.beanToMap(resource);
        beanToMap.put("yshj", NumberUtil.multiply(resource.getQuantity(), resource.getBudgetrate()));
        return beanToMap;
    }
}
